#include "modelo.h"

#define _CANT_ARCHIVOS_ABIERTOS_	10

Modelo::Modelo(unsigned char seg){
	this->terminar=false;
	srand(time(0));//genero esto para las futuras eliminaciones
}	
	
Modelo::~Modelo(){
	map<std::string,ArchivoDatos *>::iterator it = tabla_archivos.begin();	
	
	while( it != tabla_archivos.end()){
		it->second->cerrar();
		delete (it->second);
		it++;
	}
	tabla_archivos.clear();
}

bool Modelo::esta_terminado(){
	return (this->terminar);
}
void Modelo::finalizar(){
	this->terminar=true;
}

void Modelo::quitar_archivo(){
	//implementa politica random
	
	float _rand = (float)rand();
	float _max  = (float)RAND_MAX;
	int valor = (int)(( _rand / _max ) * _CANT_ARCHIVOS_ABIERTOS_);
	map<std::string,ArchivoDatos *>::iterator it = tabla_archivos.begin();	
	for(int i = 0; i < valor; i ++)
		++it;
	it->second->cerrar();
	delete (it->second);
	tabla_archivos.erase(it);
		
}

void Modelo::agregar_archivo(ArchivoDatos * a) throw(ExcepArchExistenteModelo){
	map<std::string,ArchivoDatos *>::iterator it;	
		
	it = tabla_archivos.find( a->get_nombre() );
	if( it == tabla_archivos.end() ){
		if( tabla_archivos.size() == _CANT_ARCHIVOS_ABIERTOS_ )
			quitar_archivo();
		a->agregar_observador(Buffer::get_instance());
		tabla_archivos[ a->get_nombre() ] = a;	 
	}	
	else{
		if( (it->second)->get_fd() == -1 ){
			delete (it->second);
			a->agregar_observador(Buffer::get_instance());
			tabla_archivos[ a->get_nombre() ] = a;	 
		}
		else
			throw ExcepArchExistenteModelo("Error - El archivo ya estaba ingresado.");
	}
}
ArchivoDatos& Modelo::get_archivo(std::string &nombre) throw(ExcepArchInexistente){
	map<std::string,ArchivoDatos *>::iterator it;	
	
	it = tabla_archivos.find(nombre);
	if(it == tabla_archivos.end() ){
		ArchivoDatos * a_nuevo;
		try{
			ArchivosFactory fab;
			a_nuevo = fab.hidratar(nombre);
			a_nuevo->abrir();	
			agregar_archivo(a_nuevo);
		}
		catch(ExcepSintaxisParser &err){
			throw err;
		}
		catch(ExcepArchInexistente &e){
			throw e;
		}
		catch(ExcepArchExistenteModelo &e){
			
			//Sabemos que esto nunca va a pasar, asi q no hacemos nada
		}
	}
	
	return (*tabla_archivos[nombre]);
	
}
 
void Modelo::eliminar_archivo(std::string &nombre) throw (ExcepArchInexistente){
	
	//lo busco, si no existe ni en disco propaga excep
	ArchivoDatos& arch = this->get_archivo(nombre);
	//lo borro de disco
	arch.eliminar();	
	//lo borro del modelo
	map<std::string,ArchivoDatos *>::iterator it;	
	it = tabla_archivos.find(nombre);
	if(it != tabla_archivos.end() ){
		delete (it->second);
		tabla_archivos.erase(it);
	}
	
}
